package com.mvc.framework.context;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.mvc.framework.annotation.MyAutowired;
import com.mvc.framework.annotation.MyController;
import com.mvc.framework.annotation.MyService;

public class MyApplicationContext {
	private Map<String, Object> instanceMapping = new ConcurrentHashMap<String, Object>();
	private Properties config = new Properties();
	private List<String> classCache = new ArrayList<String>();

	public MyApplicationContext(String location) {
		InputStream inputStream;

		try {

			// 定位
			inputStream = this.getClass().getClassLoader().getResourceAsStream(location);
			System.out.println("inputStream========" + inputStream);
			// 载入
			config.load(inputStream);
			// 注册
			String scanPackage = config.getProperty("scanPackage");
			System.out.println(scanPackage);

			doRegister(scanPackage);
			
			
			// 实例化
			doCreateBean();
			// 注入依赖
			populate();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void populate() {
		if (instanceMapping.isEmpty()) {
			return;
		}
		Set<Entry<String, Object>> entrySet = instanceMapping.entrySet();
		for (Entry<String, Object> entry : entrySet) {
			Field[] fields = entry.getValue().getClass().getDeclaredFields();
			for (Field field : fields) {
				if (!field.isAnnotationPresent(MyAutowired.class)) {
					continue;
				}

				MyAutowired myAutowiredannotation = field.getAnnotation(MyAutowired.class);
				String id = myAutowiredannotation.value().trim();
				if ("".equals(id)) {
					id = field.getType().getName();
					System.out.println("=========" + id);
				}
				field.setAccessible(true);

				try {
					System.out.println("entry.getValue()=====" + entry.getValue());
					System.out.println("instanceMapping.get(id)====" + instanceMapping.get(id));
					field.set(entry.getValue(), instanceMapping.get(id));
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
					continue;
				}
			}
		}
	}

	private void doCreateBean() {
		if (classCache.size() == 0) {
			return;
		}

		try {
			for (String className : classCache) {
				Class<?> clazz = Class.forName(className);

				if (clazz.isAnnotationPresent(MyController.class)) {
					String simpleName = clazz.getSimpleName();
					System.out.println("simpleName=======" + simpleName);
					System.out.println("name=========" + clazz.getName());
					String id = lowerFirstChar(simpleName);
					// 默认名为首字母小写
					instanceMapping.put(id, clazz.newInstance());
				} else if (clazz.isAnnotationPresent(MyService.class)) {
					MyService myServiceAnnotation = clazz.getAnnotation(MyService.class);
					String id = myServiceAnnotation.value();
					// 有自定义的名称
					if (!"".equals(id.trim())) {
						instanceMapping.put(id, clazz.newInstance());
						continue;
					}

					// 没有自定义的名称用其父类接口名称为id
					Class<?>[] interfaces = clazz.getInterfaces();
					for (Class<?> i : interfaces) {
						System.out.println("interfaces simpleName============" + i.getSimpleName());
						System.out.println("interfaces name===========" + i.getName());
						instanceMapping.put(i.getName(), clazz.newInstance());
					}
				} else {
					continue;
				}
			}
			System.out.println("instanceMapping========" + instanceMapping);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private String lowerFirstChar(String str) {
		char[] charArray = str.toCharArray();
		charArray[0] += 32;
		return String.valueOf(charArray);

	}

	private void doRegister(String packageName) {
		URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
		File dir = new File(url.getFile());
		File[] listFiles = dir.listFiles();
		for (File file : listFiles) {
			if (file.isDirectory()) {
				doRegister(packageName + "." + file.getName());
			} else {
				classCache.add(packageName + "." + file.getName().replace(".class", "").trim());
			}
		}
		System.out.println("classCache=====" + classCache);
	}

	public Map<String, Object> getInstanceMapping() {
		return instanceMapping;
	}

	public static void main(String[] args) {
		MyApplicationContext context = new MyApplicationContext("application.properties");

		System.out.println(context);
	}

	public Properties getConfig() {
		return config;
	}
}
